package pars;

import java.io.ObjectInputStream.GetField;
import java.util.*;

import javax.swing.plaf.basic.BasicInternalFrameTitlePane.MaximizeAction;

import lex.Token;
//import ast.Expr;

import ic.ast.*;
import ic.ast.decl.*;
import ic.ast.decl.PrimitiveType.DataType;
import ic.ast.expr.*;
import ic.ast.expr.BinaryOp.BinaryOps;
import ic.ast.expr.UnaryOp.UnaryOps;
import ic.ast.stmt.*;
import fun.grammar.Grammar;
import fun.grammar.Word;
import fun.parser.Tree;
import fun.parser.earley.EarleyParser;
import fun.parser.earley.EarleyState;
import groovy.swing.impl.DefaultAction;


public class AST {
	
	static List<DeclClass> classes=new ArrayList<DeclClass>();
	static boolean litCheck=true;

	
	public static Node constructAst(fun.parser.Tree parseTree)  
	{

		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
				
		
		switch (r.tag) {
		
		case "S": 

			return constructAst(s[0]);

			
		case "CLASSDECL*": 

			if(s.length == 2){

				DeclClass a= (DeclClass) constructAst(s[0]); 
				classes.add(a);
				constructAst(s[1]);
				Program pp=new Program(classes);
				return pp;
			}
			
			if(s.length == 1){//no class at all
				return null;	
			}
	
			
		case "CLASSDECL":  //there is an array of length 6

			ClassType classId = (ClassType)constructAst(s[1]);
			ClassType extend = (ClassType)constructAst(s[2]);
			
			List<DeclField> fields=new ArrayList<DeclField>();
			List<DeclMethod> methods=new ArrayList<DeclMethod>();

			fieldorMetHelper(s[4],fields,methods);
		
					
			if(extend!=null){ 
				return new DeclClass(classId.getLine(), classId.getClassName(), extend.getClassName(),
						fields,methods);
			}
			
			//don't have extends from superclass
			return new DeclClass(classId.getLine(), classId.getClassName(),fields,
					methods);
		
			
                
		case "CLASS_ID": 
			
			Token t= (Token)r;
			return new ClassType(t.line,t.text);
			
			
		case "EXTEND_CLASSq":
			
			if(s.length==2){
				Token t2= (Token)s[1].root;
				return new ClassType(t2.line,t2.text);
			}
			
			if(s.length==1){
				return null;
			}
			  			
			
		case "EPSILON":
			//do nothing 
			return null;

			
		default:  //should never get here 
			throw new Error("internal error");
		}
		
			
		
		
	}
	

	
	/**
	 * recursive help function to get the fields and methods of a class
	 * @param parseTree
	 * @param fields
	 * @param methods
	 * @return
	 */

	public static Node fieldorMetHelper(fun.parser.Tree parseTree,List<DeclField> fields,
			List<DeclMethod> methods){
		
		
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
				
		
		switch (r.tag){
		
			case "FIELD_OR_METHOD*":
				
				if (s.length == 2) {		
										
					fieldorMetHelper(s[0],fields,methods);
					fieldorMetHelper(s[1],fields,methods);
					
				}
		            
				if(s.length==1){ // no field or methods
					
					return null;
				}
				
			
			case "FIELD_OR_METHOD":
								
				switch(s[0].root.tag){
				
				case "FIELD":
					
					fieldorMetHelper(s[0],fields,methods);
					return null;
				
				case "METHOD":	
					
					fieldorMetHelper(s[0],fields,methods);
					
				
					
				default: 
					return null;
				
			}
		
		case "FIELD":
			
			if(s.length==4){
				
				Type field_type=(Type)fieldorMetHelper(s[0],fields,methods);
				Token tok0=(Token)s[1].root;
				
				DeclField df= (DeclField)new DeclField(field_type, tok0.text);
				fields.add(df);
				
				HandleCommaId(s[2],fields,methods,field_type);
				//return new DeclField(field_type, tok0.text);
				return null;
				
			}
		
			
			
		case "FIELD_TYPE":
			
			if(s.length==1){
				
				Type type0=(Type) fieldorMetHelper(s[0],fields,methods);
				return type0;
				
			}
			if(s.length==3){
				
				Type type0=(Type) fieldorMetHelper(s[0],fields,methods);
				int i;
				for(i=1;i<s.length+1;i++)	{
					if(i%2==0){
						type0.incrementDimension();
					}
				}
				
				return type0;
			}
			
		case "TYPE_OR_VOID":
			
			Type type4=(Type) fieldorMetHelper(s[0],fields,methods);
			return type4;
			
			
		case "TYPE":
			
			if(s.length==1){
				
				Token t3=(Token)s[0].root;
								
				switch(s[0].root.tag){
				
					case "int":{
						
						return new PrimitiveType(t3.line,DataType.INT);
					}
				
					case "string":{
						return new PrimitiveType(t3.line,DataType.STRING);
					}
					
					case "boolean":{
						return new PrimitiveType(t3.line,DataType.BOOLEAN);
					}
				
									
					default:{
						return new ClassType(t3.line,t3.text); //to check this
					}
				}
				
			}
			
			
		case "METHOD":
			
			List<Parameter> formals=new ArrayList<Parameter>();
			List<Statement> statements=new ArrayList<Statement>();
			
			if(s.length==8){//TYPE_OR_VOID ID ( FORMALSq ) { STMT* }
				Type type1=(Type) fieldorMetHelper(s[0],fields,methods);
				Token tok1=(Token)s[1].root; //the tok1.text is the id
				
				formalStatmHelper(s[3],fields,methods,formals, statements);
				
				formalStatmHelper(s[6],fields,methods,formals, statements);
				
				DeclMethod dm =new DeclVirtualMethod(type1, tok1.text ,formals, statements);
				methods.add(dm);
				return  dm;	
			}
			
			if(s.length==9){//static TYPE_OR_VOID ID ( FORMALSq ) { STMT* }
				Type type77=(Type) fieldorMetHelper(s[1],fields,methods);
				Token tok77=(Token)s[2].root; //the tok1.text is the id
				
				formalStatmHelper(s[4],fields,methods,formals, statements);
				
				formalStatmHelper(s[7],fields,methods,formals, statements);
				DeclMethod dm=new DeclStaticMethod(type77, tok77.text ,formals, statements);
				methods.add(dm);
				return  dm;
				
			}
			
			
	
				
		case "void":
			
			Token t4=(Token)r;
			return new PrimitiveType(t4.line,DataType.VOID);
			
		case "EPSILON":
			//do nothing 
			return null;
	
			
			default:  //should never get here 
				throw new Error("internal error");
			}
			
	}
	
	
	/**
	 * this method is help recursive method to get formals and statements
	 * @param parseTree
	 * @param formals
	 * @param statements
	 * @return
	 */
	
	public static Node formalStatmHelper(fun.parser.Tree parseTree,List<DeclField> fields,
			List<DeclMethod> methods,
						List<Parameter> formals,List<Statement> statements){
		
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
		
		
		switch (r.tag){
		case "FORMALSq": 
			if(s.length==2){
				
				formalStatmHelper(s[0],fields,methods,formals,statements); //formal
				formalStatmHelper(s[1],fields,methods,formals,statements); //commaformal*
				return null;
			}
			if(s.length==1){//thats epsilon
				
				return null;
			}
			
		case "FORMAL":
			
			Type type1=(Type) fieldorMetHelper(s[0],fields,methods);
			Token tok1=(Token) s[1].root; //the tok3.text is the id
			Parameter param=new Parameter(type1,tok1.text);
			formals.add(param);
			return null;
			
		case "COMMAFORMAL*":
			
			if(s.length==2){
			
				formalStatmHelper(s[0],fields,methods,formals,statements); //commaformal
				formalStatmHelper(s[1],fields,methods,formals,statements); //commaformal*
				return null;
			}
			
			if(s.length==1){//thats epsilon
			
				return null;
			}
			
		case "COMMAFORMAL":
			
			formalStatmHelper(s[1],fields,methods,formals,statements); //commaformal*
			return null;
			
		case "STMT*":
			if(s.length==1){
				return null;
			}
			
			if(s.length==2){
				
				Statement stmt=(Statement)formalStatmHelper(s[0],fields,methods,formals,statements); //STMT
				statements.add(stmt);
				
				formalStatmHelper(s[1],fields,methods,formals,statements); //STMT*
				
				return stmt;
			}
			
		case "STMT":
			
			Statement stmt=(Statement)formalStatmHelper(s[0],fields,methods,formals,statements);//IF_OR_SIMPLE_STMT
			
			return stmt; 
			
		case "IF_OR_SIMPLE_STMT":
			if(s.length==1){//IF-ELSE_OR_SIMPLE_STMT
				
				Statement stm=(Statement)formalStatmHelper(s[0],fields,methods,formals,statements); 
				return stm;
			}
			if(s.length==5){//if ( EXPR ) IF_OR_SIMPLE_STMT 
				
				Expression e=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Statement stm1=(Statement)formalStatmHelper(s[4],fields,methods,formals,statements); 
				
				return new StmtIf(e, stm1);
			}
			
		case "IF-ELSE_OR_SIMPLE_STMT":
			if(s.length==7){//if ( EXPR ) IF-ELSE_OR_SIMPLE_STMT else IF_OR_SIMPLE_STMT
				
				Expression e1=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Statement stm2=(Statement)formalStatmHelper(s[4],fields,methods,formals,statements); 
				Statement stm3=(Statement)formalStatmHelper(s[6],fields,methods,formals,statements); 
				return new StmtIf(e1, stm2,stm3);
			}
			if(s.length==1){//SIMPLE_STMT
				
				Statement stm=(Statement)formalStatmHelper(s[0],fields,methods,formals,statements); 
				return stm;	
			}
			
		case "SIMPLE_STMT":
			
			if(s.length==4){//LOCATION = EXPR ;
				
				Ref ref=(Ref)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e2=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
							
				return new StmtAssignment(ref,e2);
			}
			if(s.length==2){
				
				switch(s[0].root.tag){
				
				case "CALL"://CALL; 
					
					Call c=(Call)formalStatmHelper(s[0],fields,methods,formals,statements); 
					return new StmtCall(c);
					
				case "return"://return ;
					
					Token tok5=(Token)s[0].root;
					return new StmtReturn(tok5.line);
					
				case "break"://break ;
					Token tok6=(Token)s[0].root;
					return new StmtBreak(tok6.line);
					
				case "continue"://continue ;
						
					Token tok7=(Token)s[0].root;
					return new StmtContinue(tok7.line);
					
				default: //showld never get here
					throw new Error("internal error");	
					
				}
			}
				
			if(s.length==3){
				
				switch(s[0].root.tag){
				
				case "return"://return EXPR ;
					
					Expression e3=(Expression)formalStatmHelper(s[1],fields,methods,formals,statements);
					Token tok8=(Token)s[0].root;
					return new StmtReturn(tok8.line,e3);
					
				case "{"://{ STMT* } 
					
					List<Statement> statements1=new ArrayList<Statement>();
					formalStatmHelper(s[1],fields,methods,formals,statements1);
					Token ttt=(Token)s[0].root;
					return new StmtBlock(ttt.line, statements1);
					
					
				case "FIELD_TYPE"://FIELD_TYPE ID ;
					Type type4=(Type) fieldorMetHelper(s[0],fields,methods);
					Token tok9=(Token)s[1].root;
					
					return new LocalVariable(tok9.line, type4, tok9.text);

				}
						
			}
			
			if(s.length==5){
				
				switch(s[0].root.tag){
				
				case "while"://while ( EXPR ) STMT
					
					Expression e4=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
					
					Statement stm4=(Statement)formalStatmHelper(s[4],fields,methods,formals,statements); //TO CHECK??
					
					return new StmtWhile(e4, stm4);
					
				case "FIELD_TYPE"://FIELD_TYPE ID = EXPR ;
					Type type5=(Type) fieldorMetHelper(s[0],fields,methods);
					Token tok10=(Token)s[1].root;
					Expression e5=(Expression)formalStatmHelper(s[3],fields,methods,formals,statements);
									
					return new LocalVariable(tok10.line, type5, tok10.text, e5);
			
				}
			}
			
			
		case "EXPR"://LOGIC_OR
			
			Expression e6=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
			return e6;

			
		case "LOGIC_OR":
			
			if(s.length==3){//LOGIC_AND || LOGIC_OR
			
				Expression e7=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e8=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok10=(Token)s[1].root;
				return new BinaryOp(tok10.line, e7, BinaryOps.LOR, e8);	
			}
			
			if(s.length==1){//LOGIC_AND
				
				Expression e9=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e9;
			}
			
		case "LOGIC_AND":
			if(s.length==3){//EQ_COMPARISON && LOGIC_AND
				
				Expression e10=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e11=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok11=(Token)s[1].root;
				return new BinaryOp(tok11.line, e10, BinaryOps.LAND, e11);	
				
			}
			if(s.length==1){//EQ_COMPARISON
				
				Expression e12=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e12;
				
			}
			
		case "EQ_COMPARISON":
			if(s.length==3){
			
				Expression e13=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e14=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok12=(Token)s[1].root;
				switch(tok12.text){
				
				case "==": //RELOP == RELOP
					return new BinaryOp(tok12.line, e13, BinaryOps.EQUAL, e14);
				case "!=": //RELOP != RELOP
					return new BinaryOp(tok12.line, e13, BinaryOps.NEQUAL, e14);
				}
			}
			if(s.length==1){//RELOP
			
				Expression e15=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e15;
			}
			
		case "RELOP":
			if(s.length==3){
			
				Expression e16=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e17=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok13=(Token)s[1].root;
				switch(tok13.text){
				
				case "<"://PLUS_MINUS < PLUS_MINUS
					return new BinaryOp(tok13.line, e16, BinaryOps.LT, e17);
				case "<=": //PLUS_MINUS <= PLUS_MINUS
					return new BinaryOp(tok13.line, e16, BinaryOps.LTE, e17);
				case ">": //PLUS_MINUS > PLUS_MINUS
					return new BinaryOp(tok13.line, e16, BinaryOps.GT, e17);
				case ">=": //PLUS_MINUS >= PLUS_MINUS
					return new BinaryOp(tok13.line, e16, BinaryOps.GTE, e17);
					
				}
				
			}
			
			if(s.length==1){//PLUS_MINUS
				
				Expression e18=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e18;
			}
			
		case "PLUS_MINUS":
			if(s.length==3){
				
				Expression e19=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e20=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok14=(Token)s[1].root;
				switch(tok14.text){
				
				case "+"://PLUS_MINUS + MULT_DIV_REM
					return new BinaryOp(tok14.line, e19, BinaryOps.PLUS, e20);
				case "-": //PLUS_MINUS - MULT_DIV_REM
					return new BinaryOp(tok14.line, e19, BinaryOps.MINUS, e20);
					
				}
				
			}
			
			if(s.length==1){//MULT_DIV_REM
				
				Expression e21=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e21;
			}
			
		case "MULT_DIV_REM":
			if(s.length==3){
				
				Expression e22=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e23=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				Token tok15=(Token)s[1].root;
				switch(tok15.text){
				
				case "*"://MULT_DIV_REM * UNOP
					return new BinaryOp(tok15.line, e22, BinaryOps.MULTIPLY, e23);
				case "/": //MULT_DIV_REM / UNOP
					return new BinaryOp(tok15.line, e22, BinaryOps.DIVIDE, e23);
				case "%": //MULT_DIV_REM % UNOP
					return new BinaryOp(tok15.line, e22, BinaryOps.MOD, e23);
					
				}
				
			}
			
			if(s.length==1){//UNOP
				
				Expression e24=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e24;
			}
			
		case "UNOP": 
			if(s.length==2){
				
				Token tok16=(Token)s[0].root;
				
				switch(tok16.text){
				
				case "-": //- DOT_OR_PARA 
					if(!outOfNeg(s[1],0)){   
						litCheck=false;
					}
					Expression e25=(Expression)formalStatmHelper(s[1],fields,methods,formals,statements);
					litCheck=true;
					if(e25 instanceof Literal){
						Literal l =(Literal)e25;
						if(l.getType()==DataType.INT){
							return new Literal(l.getLine(), DataType.INT, "-"+l.getValue());
						}
					}
					
					return new UnaryOp(tok16.line, UnaryOps.UMINUS, e25);
					
				case "!": //! DOT_OR_PARA
					Expression e257=(Expression)formalStatmHelper(s[1],fields,methods,formals,statements);
					return new UnaryOp(tok16.line, UnaryOps.LNEG, e257);
				
				}
				
			}
			
			if(s.length==1){ //DOT_OR_PARA | NEW_TYPE
				
				Expression e26=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return e26;
				
			}
			
		case "NEW_TYPE":
			if(s.length==5){//new FIELD_TYPE [ EXPR ] // NewArray(Type type, Expression size)
				
				Type tp=(Type)fieldorMetHelper(s[1],fields,methods);
				Expression e27=(Expression)formalStatmHelper(s[3],fields,methods,formals,statements);
				return new NewArray(tp, e27);
				
			}
			if(s.length==7){//new FIELD_TYPE [ EXPR ] . length 
				
				Type tp1=(Type)fieldorMetHelper(s[1],fields,methods);
				Expression e28=(Expression)formalStatmHelper(s[3],fields,methods,formals,statements);
				NewArray arr=new NewArray(tp1, e28);
				Token tok17=(Token)s[5].root;
				return new Length(tok17.line, arr);
			}
			
			
		
		case "DOT_OR_PARA":
			if(s.length==3){
								
				switch(s[2].root.tag){
				
				case "length": //DOT_OR_PARA . length
					Token tok19=(Token)s[2].root;
					Expression e29=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
					return new Length(tok19.line,e29);
					
				case "SIMPLECALL": 
					
					if(s[0].root.tag=="DOT_OR_PARA"){//DOT_OR_PARA . SIMPLECALL  
					Expression e30=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
					List<Expression> arguments=new ArrayList<Expression>();
					Token tok20=helperSimpleCall(s[2], fields, methods, formals, statements, arguments);
					
					return new VirtualCall(tok20.line, e30, tok20.text, arguments);
					
					}
					
					if(s[0].root.tag=="CLASS_ID"){//CLASS_ID . SIMPLECALL
						
						ClassType cl=(ClassType)constructAst(s[0]);
						List<Expression> arguments=new ArrayList<Expression>();
						Token tok21=helperSimpleCall(s[2], fields, methods, formals, statements, arguments);
						return new StaticCall(cl.getLine(), cl.getClassName(), tok21.text, arguments);
					}
					
				case "ID"://DOT_OR_PARA . ID
					Expression e31=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
					
					List<Expression> arguments=new ArrayList<Expression>();
					Token tok251=helperSimpleCall(s[2], fields, methods, formals, statements, arguments);
					
					return new VirtualCall(tok251.line, e31, tok251.text, arguments);
					
					
				case ")": //( EXPR )
				Expression e32=(Expression)formalStatmHelper(s[1],fields,methods,formals,statements);	
				return e32; 	
					
				}
			
				
			}
			
			if(s.length==4){ //DOT_OR_PARA [ EXPR ]
				
				Expression e33=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e34=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				return new RefArrayElement(e33, e34);
				
			}
			
			if(s.length==1){//SIMPLE_EXPR
				
				Expression e35=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);	
				return e35;
			}
			
			
		case "SIMPLE_EXPR":
			if(s.length==1){
				
				switch(s[0].root.tag){
				
				case "ID":
					
					Token tok22=(Token)s[0].root;
					return new RefVariable(tok22.line, tok22.text);
					
				
				case "SIMPLECALL":
					
					List<Expression> arguments=new ArrayList<Expression>();
					Token tok23=helperSimpleCall(s[0], fields, methods, formals, statements, arguments);
					
					return new VirtualCall(tok23.line, tok23.text, arguments);
					
				case "this":
					
					Token tok24=(Token)s[0].root;
					return new This(tok24.line);
					
				case "LITERAL":
					Expression e36=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);	
					return e36;
					
				}
				
			}
			
			if(s.length==4){// new CLASS_ID ( )
				
				ClassType cl=(ClassType)constructAst(s[1]);
				return new NewInstance(cl.getLine(), cl.getClassName());
			}
			
		case "LOCATION":
			if(s.length==1){//ID
				
				Token tok25=(Token)s[0].root;
				return new RefVariable(tok25.line, tok25.text);
			}
			if(s.length==3){//EXPR . ID
				
				Token tok26=(Token)s[2].root;
				Expression e37=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				return new RefField(tok26.line, e37, tok26.text);
				
			}
			if(s.length==4){//EXPR [ EXPR ]
				
				Expression e38=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
				Expression e39=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				return new RefArrayElement(e38, e39); 
			}
			
		case "CALL":
			if(s.length==3){
				
				switch(s[0].root.tag){
				case "CLASS_ID"://CLASS_ID . SIMPLECALL
					
					ClassType cl=(ClassType)constructAst(s[0]);
					List<Expression> arguments=new ArrayList<Expression>();
					Token tok26=helperSimpleCall(s[2], fields, methods, formals, statements, arguments);
					return new StaticCall(cl.getLine(), cl.getClassName(), tok26.text, arguments);
					
				case "EXPR":// EXPR . SIMPLECALL
					
					Expression e40=(Expression)formalStatmHelper(s[0],fields,methods,formals,statements);
					List<Expression> arguments1=new ArrayList<Expression>();
					Token tok27=helperSimpleCall(s[2], fields, methods, formals, statements, arguments1);
					return new VirtualCall(tok27.line, e40, tok27.text, arguments1);
					
				}
			}
			if(s.length==1){//SIMPLECALL
				
				List<Expression> arguments=new ArrayList<Expression>();
				Token tok27=helperSimpleCall(s[0], fields, methods, formals, statements, arguments);
				
				return new VirtualCall(tok27.line, tok27.text, arguments);
				
			}
			
		case "LITERAL":
			
			Token tok29=(Token)s[0].root;
			switch(s[0].root.tag){
			
			case "INTEGER":
				
				if(litCheck){
					if(!IntegerInBounds(tok29.text)){
						System.out.println(tok29.line+":"+tok29.start+" : syntax error; numeric literal out of range: "+tok29.text);
						System.exit(0);
					}
				}
				return new Literal(tok29.line, DataType.INT, tok29.text);
				
			case "STRING":
								
				return new Literal(tok29.line, DataType.STRING, chopD(tok29.text));
				
			case "true":
				return new Literal(tok29.line,DataType.BOOLEAN, tok29.text);
			case "false":
				return new Literal(tok29.line,DataType.BOOLEAN, tok29.text);
			case "null":
				return new Literal(tok29.line,DataType.VOID, tok29.text);
				
			}
			
			
			
			
			}
							
		
			return null;	 //should never get here
		
			
		
	}
	
	/**
	 * this method is to handle comma_id*
	 * @param parseTree
	 * @param fields
	 * @param methods
	 * @param type
	 * @return
	 */
	

	public static Node HandleCommaId(fun.parser.Tree parseTree ,List<DeclField> fields,
		List<DeclMethod> methods ,Type type){
		
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
		
		switch (r.tag){
		
		case "COMMA_ID*":
			
			if(s.length==1){//s.length==1 => epsilon
				
				return null;
			}
			
			if(s.length==2) {
				
				HandleCommaId(s[0],fields,methods,type);//comma_id
				HandleCommaId(s[1],fields,methods,type);//comma_id*
				
				return null;
			}
			

			
		case "COMMA_ID":
		
			if(s.length==2){
			Token tok10 =(Token)s[1].root;
			DeclField df1= (DeclField)new DeclField(type, tok10.text);
			fields.add(df1);
			}
		
		
		default:
			return null;
		}
		
		
	}
	
	/**
	 * this method updates exprsion list and returns token id
	 * @param parseTree
	 * @param arguments
	 * @return ID
	 */
	
	
	public static Token helperSimpleCall(fun.parser.Tree parseTree,List<DeclField> fields,
			List<DeclMethod> methods,List<Parameter> formals,List<Statement> statements,List<Expression> arguments){
		
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
			
		switch(r.tag){
		case "SIMPLECALL":
			
			if(s.length==3){//ID ( )
				Token tok=(Token)s[0].root;
				return tok;
			}
		
			if(s.length==5){//ID ( EXPR COMMA_EXPR* )
				
				Token tok1=(Token)s[0].root;
				Expression ex=(Expression)formalStatmHelper(s[2],fields,methods,formals,statements);
				arguments.add(ex);
				helperSimpleCall(s[3], fields, methods, formals, statements, arguments);
				return tok1;
			}
			
		case "COMMA_EXPR*":
			if(s.length==2){//COMMA_EXPR COMMA_EXPR*
				
				helperSimpleCall(s[0], fields, methods, formals, statements, arguments);
				helperSimpleCall(s[1], fields, methods, formals, statements, arguments);
				return null;
			}
			if(s.length==1){//epsilon
				
				return null;
			}
			
		case "COMMA_EXPR":
			if(s.length==2){// , EXPR
				
				Expression ex1=(Expression)formalStatmHelper(s[1],fields,methods,formals,statements);
				arguments.add(ex1);
				return null;
			}
			
			default: return null;
		
		}
	
		
	}
	
	
/**
 * this method check if the integer value is out of bounds	
 * @param value
 * @return
 */
	
	public static boolean IntegerInBounds(String value){
	       
        try {  
                int number = Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
          // Handle the condition when str is not an Integer number.
                
                return false;
        }
       
        return true;
}
	
	/**
	 * this method check if a neg integer is out of bounds
	 * @param parseTree
	 * @param i
	 * @return false if not out of bounds otherwise exits
	 */
	public static boolean outOfNeg(fun.parser.Tree parseTree,int i){
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
		if(i==3){
			if(r.tag=="INTEGER"){
				Token t=(Token)r;
				if(!IntegerInBounds("-"+t.text)){
					System.out.println(t.line+":"+t.start+" : syntax error; numeric literal out of range: -"+t.text);
					System.exit(0);
				}
			}
		}
		if(i==3){
			return false;
		}
		i++;
		outOfNeg(s[0],i);
		return false;
	}
	
	
	public static String chopD(String s){
		String st;
		int n;
		n=s.length();
		st=s.substring(1, n-1);
		if(st.compareTo("\\n")==0){
			st="\n";	
		}
		return st;
	}
	
	
}

	

		
	
	
	

	
	
	
